2oneweek.dev

11. Scope & Scope Binding

    Tags

  • JavaScript
11. Scope & Scope Binding thumbnail

스코프의 목적

  • 범위를 제한하여 식별자 해결을 하기 위함
  • 스코프에서 식별자를 해결한다.

식별자 해결

  • 변수 이름, 함수 이름을 찾는 것
  • 이때 스코프를 사용한다.
  • 이름을 찾게 되면 값을 구할 수 있음
  • 크게는 이름을 설정하는 것도 식별자 해결
    • 변수 이름을 스코프에 등록하는 것도 식별자 해결의 한 과정

스코프는 식별자 해결을 위한 것이다.

스코프 설정 과정

function book() { var point = 123; function get() { console.log(point); } get(); } book();

첫번째 줄부터 엔진이 시작

  1. function book(){에서 function 키워드를 만나면서 엔진은 function object를 생성한다.
  2. 생성한 function object에 Scope를 결정한다. function object의 내부 프로퍼티 [[Scope]]에 결정된 Scope를 저장한다. 즉, function object 생성 시점(초기화 시점)에 Scope가 결정된다.(이렇게 생성되는 Scope를 정적 스코프라고 한다.)
    • 함수가 호출할 때 Scope를 결정하는 것을 동적 스코프라고 한다. 동적 스코프를 만드는 구문이면, 함수 호출할 때마다 스코프를 만들고, 정적 스코프는 초기화 시점에만 스코프를 만든다. Javascript는 정적스코프를 사용하면서 엔진의 효율성을 높였다.
  3. book함수를 호출하게 되면서, 엔진 컨트롤이 book함수 내부로 이동
  4. function get(){을 만나면서 엔진은 function object를 생성한다.
    • 선언문 처리 과정에서 이뤄짐
  5. get function object의 내부 프로퍼티 [[Scope]]에 스코프를 설정한다.
  6. get() 함수 호출
    • 선언문 처리 과정, 표현식 처리과정이 끝나고 엔진이 실행을 시작하는 단계


Scope Binding

binding

  • 구조적으로 결속된 상태로 만드는 것이다.

  • 바인딩의 대상은 **"프로퍼티 이름"**이다

    • 함수명과 변수명의 값은 바뀔 수 있으므로, 바인딩의 대상은 함수명, 변수명과 같은 "프로퍼티 이름"이다.
  • binding의 목적은 "스코프를 설정"하여 식별자를 해결하기 위함이다.

  • binding은 바인딩 되는 시점을 기준으로 2가지로 나뉜다.

    1. 정적 바인딩 (Lexical Binding, Static Binding)
    2. 동적 바인딩 (Dynamic Binding)

Lexical Binding(정적 바인딩)

  • 함수가 호출되었을 때, 초기화 단계에서 바인딩
  • 함수 선언문 이름을 바인딩
  • 표현식(변수 함수)이름을 바인딩한다. 자바스크립트는 대부분 정적바인딩을 한다.

Dynamic Binding(동적 바인딩)

  • 함수가 실행될 때 바인딩
  • eval() 함수, with문


binding 시점의 중요성

binding할 때 Scope가 결정되기 때문에, 매우 중요함

우리는 function Object 생성 시점에 Scope가 결정되는 것으로 알고 있다. JS 엔진은, function Object를 생성하고, 생성한 function Object의 내부 프로퍼티 [[Scope]]에 현재(타겟) 함수의 Scope를 설정한다. 이렇게 설정된 Scope는 절대 변경되지 않는다. 따라서 "정적" Scope, "정적 환경"이라고 할 수 있는 것이다. 이렇게 Scope를 설정하는 것이 Binding 이다.

function book() { var point = 100; function add() { point += 200; } function get() { return point; } }

book 함수 내부에 선언된 함수들의 Scope는 모두 동일하다.

내부 프로퍼티에 Scope를 삽입하므로, add function object와 get function object의 [[Scope]]의 값은 동일하다.

add를 호출하고 get을 호출하면, 왜 100이 아니라 300이 호출될까? 각자의 Scope가 있는데, 100이 호출되어야 하는 것이 아닌가? 라고 생각할 수도 있을 것이다.

function object마다 point의 값을 따로 갖는 것이 아니다. Scope를 binding할 때 "이름"만을 binding한다. 따라서 식별자 해결에 있어 동일한 이름을 사용할 뿐이지, binding은 변수의 값과는 아무런 상관이 없다.

Scope binding (정적 바인딩의 경우)

function book() { var point = 100; function add(param) { point += param; } var get = function () { return point; }; add(200); console.log(get()); } book();

book() 함수가 호출된다. 함수 안으로 엔진 컨트롤이 이동하여 초기화단계가 실행된다.

  • 실행 컨텍스트를 만들기 위한 초기화 작업이 시작되는 것
  • 선언적 환경 레코드에 변수 "이름"과 함수 "이름을" 선언적 환경 레코드에 바인딩하기 시작한다.

  1. 엔진은 선언문 처리를 시작한다.

    • function add를 만나면 function object를 생성하고, add함수가 속한 Scope를 add function object의 [[Scope]]에 설정한다.
      • add라는 이름을 add function object의 선언적환경레코드에 바인딩한다.

어디에 있는 선언적 환경 레코드지?? book의 실행컨텍스트에 있는 것인가book() 함수에서 point 변수를 식별할 때는 선언적 환경 레크드에 설정됩니다. 반면, add() 함수 안에서는 book() 함수 안에 작성된 모든 변수가 외부 렉시컬 환경 참조에 설정됩니다.

  1. 엔진은 표현식 처리를 시작한다.

    • var point를 만나면서 point라는 이름을 선언적 환경 레코드에 바인딩한다.
    • var get = function(){}을 만나면서, function object를 생성하고, Scope를 할당해 준 후, get이라는 이름을 선언적 환경 레코드에 바인딩한다.
    • 여기까지 함으로써 바인딩이 끝난다. 함수와 변수의 식별자가 해결된다.
  2. 이제 엔진은 코드를 실행한다.

    • point 변수에 100을 할당
    • get = function()을 만나 function object를 생성하고 [[Scope]]에 get 이 속한 범위를 설정한다.
    • add함수 호출
  3. add 함수로 엔진 컨트롤이 이동한다.

    • 함수로 엔진 컨트롤이 이동했다는 것은, 이미 add라는 function object가 있어서 호출했다는 것이다. 그리고 현재 콜스택의 최상단은 add의 실행컨텍스트다.
    • 현재 "실행컨텍스트"(add함수의 실행컨텍스트)의 선언적 환경 레코드가 Scope가 되어 현재 Scope에서 point라는 이름을 찾게된다.
    • 없으므로, add라는 function object의 [[Scope]]를 현재 Scope로 삼고 point 라는 이름을 찾는다.([[Scope]]를 이용해서 함수가 속한 Scope를 나의 Scope처럼 사용할 수 있는 것이다.)
      • add의 function object의 [[Scope]]는 book object다.
    • book object의 선언적 환경 레코드에 point라는 이름이 있으므로, point라는 이름의 식별자 해결이 가능하고 100이라는 값을 들고올 수 있게 되었다. 이제 덧셈을 하고 끝난다.
  4. get() 함수 호출, 엔진 컨트롤 get()함수로 이동

    • 이제 콜스택의 최상단은 get의 실행컨텍스트다.
    • 현재 Scope에서는(실행 컨텍스트의 선언적 환경 레코드에서) point라는 이름을 찾을 수 없다.
    • get function object의 [[Scope]]를 Scope로 삼고 식별자 해결을 한다. 식별자 해결이 되었으므로 point의 값을 가져와서 반환한다.
Written by@2-one-week
현재 블로그 개발 중

GitHubLinkedIn